package core

import (
	"bytes"
	"errors"
)

type Subscriber struct {
	ClientID  uint64
	TopicsQos map[string]uint8 // 订阅的主题和对应的QoS等级
}

func NewSubscriber(clientID uint64) *Subscriber {
	return &Subscriber{
		ClientID:  clientID,
		TopicsQos: make(map[string]uint8),
	}
}
func (s *Subscriber) AddTopic(data *Subscriber) {
	if data == nil {
		return
	}
	for topic, qos := range data.TopicsQos {
		s.TopicsQos[topic] = qos
	}
}
func (s *Subscriber) RemoveTopic(data *Subscriber) {
	if data == nil {
		return
	}
	for topic := range data.TopicsQos {
		delete(s.TopicsQos, topic)
	}
}

func EncodeSubscribeMsg(subscriber *Subscriber) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)
	if err := bufs.WriteByte(MQ_Sub); err != nil {
		return nil, err
	}

	if _, err := WriteUint64(bufs, subscriber.ClientID); err != nil {
		return nil, err
	}

	if len(subscriber.TopicsQos) == 0 {
		return nil, errors.New("no topics to subscribe")
	}

	//写入主题数量
	if _, err := WriteUint16(bufs, uint16(len(subscriber.TopicsQos))); err != nil {
		return nil, err
	}

	for topic, qos := range subscriber.TopicsQos {
		if _, err := WriteString(bufs, topic); err != nil {
			return nil, err
		}
		if err := bufs.WriteByte(qos); err != nil {
			return nil, err
		}
	}

	return bufs.Bytes(), nil
}
func DecodeUnSubscribeMsg(data []byte) (*Subscriber, error) {
	return DecodeSubscribeMsg(data, false)
}
func DecodeSubscribeMsg(data []byte, bSub bool) (*Subscriber, error) {
	if len(data) < 9 {
		return nil, errors.New("data too short to decode SubscribeMsg")
	}
	if bSub {
		if data[0] != MQ_Sub {
			return nil, errors.New("invalid message type")
		}
	} else {
		if data[0] != MQ_UnSub {
			return nil, errors.New("invalid message type")
		}
	}

	clientID, err := ReadUint64FromBytes(data[1:9])
	if err != nil {
		return nil, err
	}

	subscriber := &Subscriber{
		ClientID:  clientID,
		TopicsQos: make(map[string]uint8),
	}

	topicCount, err := ReadUint16FromBytes(data[9:])
	if err != nil {
		return nil, err
	}

	offset := 11 // 8 bytes for ClientID + 2 bytes for topic count
	for i := uint16(0); i < topicCount; i++ {
		topic, err := ReadStringFromBytes(data[offset:])
		if err != nil {
			return nil, err
		}
		offset += 4 + len(topic) // 4 bytes for length + topic length
		qos := data[offset]
		subscriber.TopicsQos[topic] = qos
		offset += 1 // move past the QoS byte
	}

	return subscriber, nil
}

// ///////////////////////////////////////////////////////////////
type TopicAck struct {
	Name    string
	Qos     uint8
	Command bool   //操作命令,true为注册，false为反注册
	Result  bool   //操作结果
	Error   string //如果正确，则为字符串"nil"，反之为错误字符串
}

type SubscriberAck struct {
	ClientID uint64
	Topics   map[string]*TopicAck
}

func NewSubscriberAck() *SubscriberAck {
	return &SubscriberAck{Topics: make(map[string]*TopicAck)}
}
func NewTopicAck() *TopicAck {
	return &TopicAck{}
}
func EncodeUnSubscribeAckMsg(ack *SubscriberAck) ([]byte, error) {
	data, err := EncodeSubscribeAckMsg(ack)
	data[0] = MQ_UnSubAck
	return data, err
}
func EncodeSubscribeAckMsg(ack *SubscriberAck) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)
	bufs.WriteByte(MQ_SubAck)
	WriteUint64(bufs, ack.ClientID)
	WriteUint16(bufs, uint16(len(ack.Topics)))
	for _, topic := range ack.Topics {
		WriteString(bufs, topic.Name)
		bufs.WriteByte(topic.Qos)
		if topic.Command {
			bufs.WriteByte(byte(0x01))
		} else {
			bufs.WriteByte(byte(0x00))
		}
		if topic.Result {
			bufs.WriteByte(byte(0x01))
		} else {
			bufs.WriteByte(byte(0x00))
		}
		WriteString(bufs, topic.Error)
	}

	return bufs.Bytes(), nil
}
func DecodeSubscribeAckMsg(data []byte) (*SubscriberAck, error) {
	if data[0] != MQ_SubAck {
		return nil, errors.New("invalid message type")
	}
	index := 1
	obj := NewSubscriberAck()

	var err error
	if obj.ClientID, err = ReadUint64FromBytes(data[1:]); err != nil {
		return nil, err
	}
	index += 8

	var num uint16
	if num, err = ReadUint16FromBytes(data[index:]); err != nil {
		return nil, err
	}
	index += 2
	for a := 0; a < int(num); a++ {
		t := NewTopicAck()
		if t.Name, err = ReadStringFromBytes(data[index:]); err != nil {
			return nil, err
		}
		index += 4 + len(t.Name)

		t.Qos = data[index]
		index++

		if data[index] == byte(0x01) {
			t.Command = true
		} else {
			t.Command = false
		}
		index++

		if data[index] == byte(0x01) {
			t.Result = true
		} else {
			t.Result = false
		}
		index++

		if t.Error, err = ReadStringFromBytes(data[index:]); err != nil {
			return nil, err
		}
		obj.Topics[t.Name] = t
	}

	return obj, nil
}
